import { Constructor, Node, log } from "cc";
import { ModuleBase } from "./ModuleBase";


export  class ModuleManager{
    // Map Array Set
    // 存储模块的容器
    private _modules:Set<ModuleBase> = new Set();
    // 单例
    private static _instance:ModuleManager = null;
    static get Instance(){
        this._instance = this._instance || new ModuleManager();
        return this._instance;
    }

    // 添加模块的接口
    // 基类类型当做参数  实参是子类对象 那么这里相当于
    // 用基类类型的指针 接收了子类类型的对象
    addModule(module:ModuleBase):void{
        if (!module) {
            return;
        }
        // set容器的存储接口
        this._modules.add(module);
    }
   
    // set容器
    // getComponent<T extends Component>(classConstructor: __private._types_globals__Constructor<T>): T | null;
    //  模仿 getComponent()的写法
    getModule<T extends ModuleBase>(type:Constructor<T>):T | null{
        // 把set容器内的所有元素的集合 转化成数组
        const arr = Array.from(this._modules.values());
        for (const module of arr) {
            // 遍历数组 判断module是不是type类型
            if (module instanceof type) {
                return module as T;
            }
        }
        return null;
    }
    
    getModuleByName<T extends ModuleBase>(name:string):T | null{
        const arr = Array.from(this._modules.values());
        for (const module of arr) {
            // log(module.constructor.name)
            // 遍历数组 判断module是不是type类型
            if (module.constructor.name === name) {
                return (module as T);
            }
        }
        return null;
    }
    
    removeModule(module:ModuleBase){
        // 从容器中移除模块
        this._modules.delete(module);
        module.node.destroy();
    }

    // 移除接口
    removeModuleByName(name:string){
        const module = this.getModuleByName(name);
        this._modules.delete(module);
        module.node.destroy();
    }
    clear(){
        this._modules.clear();
    }

    // 发送消息 目的是为了让某个模块执行某个函数
    // moduleName 找模块
    // msg 消息名
    // args 剩余参数 给函数执行的参数
    sendMsg(moduleName:string,msg:string,...args){
        // 获取目标模块
        const module = this.getModuleByName(moduleName);
        // 如果没有获取到 则什么也不做
        if (!module) {
            return;
        }
        // 获取目标模块中 和消息同名的函数
        const callback = module[msg];
        // 获取到函数 则执行
        if (callback) {
            // 通过apply绑定函数的this指向 并传递参数
            callback.apply(module,[...args]);
            return;
        }
        // 如果没有找到消息同名函数 则让模块自己去执行对应消息事件
        module.callEvent(msg,...args);
    }
}

